package org.sixtythousand.joker.servlet.session;

import org.sixtythousand.joker.http.HttpHandler;
import org.sixtythousand.joker.http.HttpRequest;
import org.sixtythousand.joker.http.HttpResponse;
import org.sixtythousand.joker.servlet.SimpleRequest;
import org.sixtythousand.joker.servlet.servlet.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.DispatcherType;
import javax.servlet.SessionCookieConfig;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;

/**
 * @author zhoulk
 * @date 2023/10/13 15:44
 * @desc
 */
public class SessionHandler extends HttpHandler {

    private static final Logger LOG = LoggerFactory.getLogger(SessionHandler.class);


    public static final String DEFAULT_SESSION_ID = "JOKER_ID";
    protected int maxCookieAge = -1;
    protected int refreshCookieAge;
    protected Context context;
    private SessionCache sessionCache;
    private SessionManager sessionManager;

    @Override
    protected void doHandler(HttpRequest request, HttpResponse response) {
        SimpleRequest simpleRequest = (SimpleRequest) request;
        HttpSession existingSession = null;
        switch (simpleRequest.getDispatcherType()) {
            case REQUEST:
                existingSession = doRequest(simpleRequest);
                break;
            default:
                break;
        }

        if (existingSession != null) {
            HttpCookie cookie = access(existingSession, simpleRequest.isSecure());
            if (cookie != null
                    && (simpleRequest.getDispatcherType() == DispatcherType.REQUEST
                    || simpleRequest.getDispatcherType() == DispatcherType.ASYNC)) {
                simpleRequest.getResponse().updateCookie(cookie);
            }
        }

        // 调用下一个handler
        nextHandle(request, response);
    }

    protected HttpSession doRequest(SimpleRequest request) {
        checkRequestedSessionId(request);

        request.setSessionHandler(this);
        return request.getSession(false);
    }

    /**
     * 更新会话时间，以及cookie过期时更新cookie
     *
     * @param session
     * @param secure
     * @return
     */
    public HttpCookie access(HttpSession session, boolean secure) {
        long now = System.currentTimeMillis();

        Session s = (Session) session;


        if (s.access(now)) {
            // Do we need to refresh the cookie?
            if (isUsingCookies() &&
                    ((getSessionCookieConfig().getMaxAge() > 0 && getRefreshCookieAge() > 0 &&
                            ((now - s.getCookieSetTime()) / 1000 > getRefreshCookieAge())))) {
                HttpCookie cookie = getSessionCookie(session, context == null ? "/" : (context.getContextPath()), secure);
                s.cookieSet();
                return cookie;
            }
        }
        return null;
    }

    public HttpSession newHttpSession(SimpleRequest request) {
        String sessionId = sessionManager.newSessionId(request);
        Session session = sessionManager.newSession(request, sessionId);
        sessionCache.cacheSession(sessionId, session);
        request.setSession(session);
        return session;
    }

    public boolean isValid(HttpSession session) {
        if (session == null) {
            return false;
        }
        // todo
        return true;
    }

    public HttpCookie getSessionCookie(HttpSession session, String contextPath, boolean requestIsSecure) {
        if (!isUsingCookies()) {
            return null;
        }

        SessionCookieConfig cookieConfig = getSessionCookieConfig();

        // todo create sessionCookie


        return null;

    }


    public boolean isUsingCookies() {

        return true;
    }

    public SessionCookieConfig getSessionCookieConfig() {
        return null;
    }

    protected void checkRequestedSessionId(SimpleRequest request) {
        String requestedSessionId = request.getRequestedSessionId();
        if (requestedSessionId != null) {
            HttpSession session = sessionCache.getSession(requestedSessionId);
            if (session != null && isValid(session)) {
                request.setSession(session);
            }
            return;
        }

        // 如果request对象不存在sessionId， 则尝试从cookie获取
        HttpSession session = null;

        if (isUsingCookies()) {
            String sessionCookie = getSessionCookieName(getSessionCookieConfig());
            Cookie[] cookies = request.getCookies();
            for (Cookie cookie : cookies) {
                if (sessionCookie.equalsIgnoreCase(cookie.getName())) {
                    String id = cookie.getValue();
                    if (session == null) {
                        HttpSession s = getSession(id);
                        if (isValid(s)) {
                            requestedSessionId = id;
                            session = s;
                            request.setSession(session);
                        } else {
                            LOG.debug("No session found for session cookie id {}", id);
                            requestedSessionId = id;

                        }
                    } else {
                        if (!session.getId().equals(id)) {
                            HttpSession s = getSession(id);
                            if (isValid(s)) {
                                LOG.debug("exists multiple different valid session ids: {}, {}", requestedSessionId, id);
                                // todo 当存在多个有效的sessionId时，抛出异常
                                throw new RuntimeException("Duplicate valid session cookies: " + requestedSessionId + " ," + id);
                            }
                        }
                    }
                }
            }
        } else {
            LOG.debug("cookies not enabled ...  ");
            // todo 当未启用时， 尝试从其它地方获取sessionId
        }

        request.setRequestSessionId(requestedSessionId);

    }

    public static String getSessionCookieName(SessionCookieConfig config) {
        return (config == null || config.getName() == null) ? DEFAULT_SESSION_ID : config.getName();
    }

    public HttpSession getSession(String sessionId) {
        // todo
        return null;
    }


    public int getRefreshCookieAge() {
        return refreshCookieAge;
    }
}
